/*
	The Raja Toolkit.
	Copyright (C) 2011 Raja-Toolkit Foundation

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 3.0 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef TRANSFORMS_HPP
#define TRANSFORMS_HPP

#include "../types.hpp"
#include "vector.hpp"
#include "matrix.hpp"
#include "quaternion.hpp"

namespace raja
{
namespace math
{

/// @name orthogonal 2d projection matrix
/// @{
template<typename T>
tmat4<T> mat4_ortho(T left, T right, T bottom, T top);

template<typename T>
tmat4<T> mat4_ortho(const tvec2<T>& lb, const tvec2<T>& rt);
/// @}

/// @name orthogonal 3d projection matrix
/// @{
template<typename T>
tmat4<T> mat4_ortho(T left, T right, T bottom, T top, T near, T far);

template<typename T>
tmat4<T> mat4_ortho(const tvec3<T>& lbn, const tvec3<T>& rtf);
/// @}

///
/// perspective projection matrix
/// @param fovy field of view in radians and in y direction
/// @param aspect the aspect ratio
/// @param near near plane value
/// @param far far plane value
///
template<typename T>
tmat4<T> mat4_perspective(T fovy, T aspect, T near, T far);

/// translation matrix
template<typename T>
tmat4<T> mat4_translation(const tvec3<T>& trans);

/// scale matrix
template<typename T>
tmat4<T> mat4_scale(const tvec3<T>& scale);

/// @name rotation matrix
/// @{
template<typename T>
tmat4<T> mat4_rotation(const tquat<T> &q);

template<typename T>
tmat4<T> mat4_rotation(T angle, const tvec3<T>& axis);
/// @}

///
/// lookat matrix
/// @param eye the eye position
/// @param dest the eye destination position
/// @param up the up vector
/// @return the lookat matrix
///
template<typename T>
tmat4<T> mat4_lookat(const tvec3<T>& eye, const tvec3<T>& dest, const tvec3<T>& up);

///
/// frustum matrix
/// @param lbn left/bottom/near
/// @param rtf right/top/far
/// @return the frustum matrix
/// @note both near and far must be positive (the function will compute the frustum regardless even if it is not valid)
///
template<typename T>
tmat4<T> mat4_frustum(const tvec3<T>& lbn, const tvec3<T>& rtf);

///
/// project a point to the screen
/// @param world world matrix (or modelview matrix)
/// @param persp perspective matrix
/// @param lb view left/bottom
/// @param rt view right/top
/// @param pt the input point
/// @return the projected point
///
template<typename T>
tvec3<T> project(const tmat4<T>& world, const tmat4<T>& persp, const tvec2<T>& lb, const tvec2<T>& rt, const tvec3<T>& pt);

///
/// unproject a point to the 3d system
/// @param world world matrix (or modelview matrix)
/// @param persp perspective matrix
/// @param lb view left/bottom
/// @param rt view right/top
/// @param pt the input point
/// @return the unprojected point
///
template<typename T>
tvec3<T>					unproject(const tmat4<T>& world, const tmat4<T>& persp, const tvec2<T>& lb, const tvec2<T>& rt, const tvec3<T>& pt);


///
/// @brief convert from world coordinates to local coordinates
/// @param m world matrix
/// @param in the input world coordinates
/// @return local coordinates
///
template<typename T>
tvec3<T>					world3_to_local3(const tmat4<T>& world, const tvec3<T>& in);

///
/// @brief transform a vec3 by a mat4
/// @param m matrix
/// @param in input vector
/// @return the transformed vector
///
template<typename T>
tvec3<T>					transform(const tmat4<T>& m, const tvec3<T>& in);

///
/// @brief transform a vec4 by a mat4
/// @param m matrix
/// @param in input vector
/// @return the transformed vector
///
template<typename T>
tvec4<T>					transform(const tmat4<T>& m, const tvec4<T>& in);

}	// namespace math
}	// namespace raja
#endif // TRANSFORMS_HPP
